/*******************************************************************************
**
** Copyright (c) 2011 - The OWE Team
**
** This file is part of OWE.
**
** OWE is a free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; version
** version 2.1 of the License.
**
** OWE is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with OWE. If not, see <http://www.gnu.org/licenses/>.
**
*******************************************************************************/

#include <cstring>

#include <tut/tut.hpp>
#include <tut/tut_console_reporter.hpp>

#include <owe/ustring.h>

OWE_USE_NAMESPACE

namespace tut
{
    test_runner_singleton runner;

    struct UString_data {};

    typedef test_group<UString_data> testgroup;
    testgroup shared_ptr_group("UString");
    typedef testgroup::object testobject;

    template<>
    template<>
    void testobject::test<1>() {
        set_test_name("UString::UString(const char *str)");

        UString none;
        ensure(strcmp(none.data(), "") == 0);
        ensure(none.size() == 0);

        UString empty(0);
        ensure(strcmp(empty.data(), "") == 0);
        ensure(empty.size() == 0);

        UString ascii("test123");
        ensure(strcmp(ascii.data(), "test123") == 0);
        ensure(ascii.size() == 7);

        // Do all compilers support this? Of course will require
        // a UTF-8 environment.
        UString japanese("ブラジル");
        ensure(strcmp(japanese.data(), "ブラジル") == 0);
        ensure(japanese.size() == 4);
    }

    template<>
    template<>
    void testobject::test<2>() {
        set_test_name("UString::UString(const UString &other)");

        UString none1;
        UString none2(none1);
        ensure(strcmp(none1.data(), none2.data()) == 0);
        ensure(strcmp(none1.data(), "") == 0);

        UString empty1(0);
        UString empty2(empty1);
        ensure(strcmp(empty1.data(), empty2.data()) == 0);
        ensure(strcmp(empty2.data(), "") == 0);

        UString string1("test123");
        UString string2(string1);
        ensure(strcmp(string1.data(), string2.data()) == 0);
        ensure(strcmp(string2.data(), "test123") == 0);
    }

    template<>
    template<>
    void testobject::test<3>() {
        set_test_name("UString UString::&operator=(const UString &other)");

        UString none1;
        UString none2;
        none2 = none1;
        ensure(strcmp(none1.data(), none2.data()) == 0);
        ensure(strcmp(none1.data(), "") == 0);

        UString empty1(0);
        UString empty2(0);
        empty2 = empty1;
        ensure(strcmp(empty1.data(), empty2.data()) == 0);
        ensure(strcmp(empty2.data(), "") == 0);

        UString string1("test123");
        UString string2("test321");
        string2 = string1;
        ensure(strcmp(string1.data(), string2.data()) == 0);
        ensure(strcmp(string2.data(), "test123") == 0);

        string2 = string2;
        ensure(strcmp(string2.data(), "test123") == 0);
    }

    template<>
    template<>
    void testobject::test<4>() {
        set_test_name("UString &UString::append(const UString &ustr)");

        UString none1;
        UString none2;
        none1.append(none2);
        ensure(strcmp(none1.data(), "") == 0);

        UString empty1(0);
        UString empty2(0);
        empty1.append(empty2);
        ensure(strcmp(empty1.data(), "") == 0);
        empty1.append("test123");
        ensure(strcmp(empty1.data(), "test123") == 0);

        UString japanese("ブラジル");
        UString portuguese("maçã");
        UString japt = japanese + portuguese;
        ensure(strcmp(japt.data(), "ブラジルmaçã") == 0);
        ensure(japt.size() == 8);
    }

    template<>
    template<>
    void testobject::test<5>() {
        set_test_name("bool UString::operator==(const char *uchar)");

        UString none;
        ensure(none == "");
        ensure(none == UString());

        UString empty(0);
        ensure(empty == "");
        ensure(empty == UString(0));

        UString test1("abcd");
        ensure(test1 != "ABCD");
        ensure(test1 != UString("ABCD"));

        UString test2("tEsT123");
        ensure(test2 == "tEsT123");
        ensure(test2 == UString("tEsT123"));

        UString test3("123aaa");
        ensure(test3 != "123AAA");
        ensure(test3 != UString("123AAA"));

        UString test4("123");
        ensure(test4 != "123AAA");
        ensure(test4 != UString("123AAA"));

        UString test5("123aaa");
        ensure(test5 != "123");
        ensure(test5 != UString("123"));

        UString test6("123aaa");
        ensure(test6 != "");
        ensure(test6 != UString(""));

        UString japanese("ブラジル");
        ensure(japanese == "ブラジル");
        ensure(japanese == UString("ブラジル"));

        UString portuguese("maçã");
        ensure(portuguese == "maçã");
        ensure(portuguese == UString("maçã"));
    }

    template<>
    template<>
    void testobject::test<6>() {
        set_test_name("bool UString::operator<(const char *uchar)");

        UString none;
        ensure((none < "") == false);
        ensure((none < UString()) == false);
        ensure((none > "") == false);
        ensure((none > UString()) == false);

        UString empty(0);
        ensure((empty < "") == false);
        ensure((empty < UString(0)) == false);
        ensure((empty > "") == false);
        ensure((empty > UString(0)) == false);

        UString test1("123bbb");
        ensure(test1 < "123ccc");
        ensure(test1 < UString("123ddd"));
        ensure(test1 > "123aaa");
        ensure(test1 > UString("123123"));

        UString test2("AAB123");
        ensure(test2 < "AAC123");
        ensure(test2 < UString("aab123"));
        ensure(test2 > "AAA123");
        ensure(test2 > UString("123123"));

        UString test3("aaa");
        ensure(test3 != "aaaa");
        ensure(test3 < UString("aaaa"));
        ensure(test3 > "a");
        ensure(test3 > UString("1"));

        UString portuguese("maçã");
        ensure(portuguese > "maca");
    }

    // The methods bellow are tested all around, no retesting needed:
    // const char *UString::data() const
    // int UString::size() const
}

int main(void)
{
    tut::console_reporter reporter;
    tut::runner.get().set_callback(&reporter);
    tut::runner.get().run_tests();

    return reporter.all_ok() ? 0 : 1;
}
